package com.ruoyi.xuexiao.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.utils.CoordinateUtil;
import com.ruoyi.utils.ZipUtil;
import com.ruoyi.xuexiao.domain.entity.KsTc;
import com.ruoyi.xuexiao.domain.param.KsTcParam;
import com.ruoyi.xuexiao.mapper.KsTcxMapper;
import com.ruoyi.xuexiao.service.KsTcsService;
import io.netty.util.internal.StringUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKTWriter;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
 * 矿山图层业务层
 * @author 窦凯欣
 */
@Service(value = "ksTcsService")
@AllArgsConstructor
public class KsTcsServiceImpl extends ServiceImpl<KsTcxMapper, KsTc> implements KsTcsService
{
    // 矿山图层数据层
    private KsTcxMapper ksTcxMapper;
    /**
     * 上传zip解压shp文件信息存入数据库
     * @param file
     * @throws IOException
     * @author 窦凯欣
     */
    @Override
    public Boolean uploadShp(MultipartFile file) throws IOException {
        // 创建临时目录
        Path tempDir = Files.createTempDirectory("");
        // 创建临时ZIP文件
        File zipFile = Files.createTempFile(tempDir, null, ".zip").toFile();
        file.transferTo(zipFile);
        // 判断是否为zip文件
        if (!ZipUtil.isZipFile(file))
        {
            throw new RuntimeException("请上传zip文件");
        }
        // 解压ZIP文件
        File unzipDir = Files.createTempDirectory(tempDir, "unzip").toFile();
        cn.hutool.core.util.ZipUtil.unzip(zipFile, unzipDir);
        // 查找解压后的SHP文件
        File shpFile = Files.list(unzipDir.toPath())
                .filter(path -> path.toString().endsWith(".shp"))
                .findFirst()
                .orElseThrow(() -> new IOException("Shapefile not found"))
                .toFile();
        // 读取SHP文件
        Map<String, Object> map = new HashMap<>();
        try {
            map.put("url", shpFile.toURI().toURL());
            // 处理编码问题
            map.put("charset", Charset.forName(getShapeFileCharsetName(shpFile)));
        } catch (Exception e) {
            throw new IOException("Invalid shapefile URL", e);
        }
        // 创建工厂对象
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
        ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createDataStore(map);
        // 读取要素
        try (SimpleFeatureIterator iterator = dataStore.getFeatureSource().getFeatures().features()) {
            while (iterator.hasNext()) {
                SimpleFeature feature = iterator.next();
                Iterator<Property> it = feature.getProperties().iterator();
                Map<String, String> mapr = new HashMap<>();
                KsTc ksTc = new KsTc();
                while(it.hasNext())
                {
                    Property next = it.next();
                    // 将解析shp文件的数据以Key_Value形式存储到map集合中
                    mapr.put(next.getName().toString(), next.getValue().toString());
                }
                // 投影坐标转地理坐标的十进制度
                String geo = CoordinateUtil.coordinateTransform(feature, 4490).toString();
                // 添加ks_tc数据
                setData(mapr, ksTc, geo);
            }
        } finally {
            // 释放资源
            dataStore.dispose();
        }
        return true;
    }

    /**
     * 添加ks_tc数据
     * @param mapr
     * @param ksTc
     * @author 窦凯欣
     */
    @SneakyThrows
    private void setData(Map<String, String> mapr, KsTc ksTc, String geo)
    {
        // 将map数据转换为JSON字符串
        String jsonString = JSON.toJSONString(mapr);
        // 将json格式的字符传转换为对象
        KsTcParam ksTcParam = JSON.parseObject(jsonString, KsTcParam.class);
        // 设置对象属性数据
        ksTc.setXkzh(ksTcParam.getXKZ());
        String monthAndYaer = ksTcParam.getYXQZ();
        String[] split = monthAndYaer.split("/");
        ksTc.setMonth(Integer.parseInt(split[1]));
        ksTc.setYear(Integer.parseInt(split[0]));
        ksTc.setLon(ksTcParam.getZBX());
        ksTc.setGeom(geo);
        ksTc.setLat(ksTcParam.getZBY());
        ksTc.setWtlx(ksTcParam.getWTLX());
        ksTc.setZdfs(ksTcParam.getZDFS());
        ksTc.setKczt(ksTcParam.getKCZT());
        ksTc.setZdmj(ksTcParam.getZDMJ());
        ksTc.setDt(ksTcParam.getDT());
        // 添加数据
        ksTcxMapper.addData(ksTc);
    }

    /**
     * 设置字符编码
     * @param file
     * @throws Exception
     * @author 窦凯欣
     */
    private static String getShapeFileCharsetName(File file) throws Exception {
        // 判断是否为文件
        if (file.exists() && !file.isFile()) {
            return "GBK";
        }
        String encode = "GBK";
        BufferedReader reader = null;
        try {
            // 读取文件流
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            // 一次读入一行，直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                // 显示行号
                if ("UTF-8".equals(tempString.toUpperCase())) {
                    encode = "UTF-8";
                    break;
                }
                break;
            }
            // 释放资源
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    // 释放资源
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
        return encode;
    }

    /**
     * 查询shp文件信息添加数据并分页
     * @author 窦凯欣
     */
    @Override
    public List<KsTc> mountDataAll(String xkzh)
    {
        // 查询，可选条件许可证号
        List<KsTc> ksTcs = ksTcxMapper.selectList(new LambdaQueryWrapper<KsTc>()
                .eq(!StringUtil.isNullOrEmpty(xkzh), KsTc::getXkzh, xkzh));
        return ksTcs;
    }

    /**
     * 查询ks全部数据
     * @author 窦凯欣
     */
    @Override
    public List<KsTc> getKsDataAll()
    {
        List<KsTc> ksTcs = baseMapper.selectList(null);
        ksTcs.stream()
                .forEach(r -> {
                    try {
                        // 将 WKB 组合字符串转换为字节数组
                        byte[] wkbBytes = hexStringToByteArray(r.getGeom());
                        // 创建 WKBReader 实例
                        WKBReader wkbReader = new WKBReader();
                        // 从 WKB 字节数组中读取几何图形
                        Geometry geometry = wkbReader.read(wkbBytes);
                        // 将几何图形转换为 WKT
                        WKTWriter wktWriter = new WKTWriter();
                        String wkt = wktWriter.write(geometry);
                        // 设置 WKT 属性
                        r.setGeom(wkt);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
        return ksTcs;
    }


    /**
     * 将十六进制字符串转换为字节数组
     * @param s 要转换的十六进制字符串
     * @return 转换后的字节数组
     * @author 窦凯欣
     */
    private static byte[] hexStringToByteArray(String s) {
        // 获取字符串的长度
        int len = s.length();
        // 创建一个字节数组，其长度为十六进制字符串长度的一半
        // 因为两个十六进制字符代表一个字节
        byte[] data = new byte[len / 2];
        // 循环遍历字符串，每次处理两个字符
        for (int i = 0; i < len; i += 2) {
            // 将当前字符和下一个字符分别转换为十六进制表示的数值，并组合成一个字节
            // Character.digit(char ch, int radix) 返回在指定基数中的数值
            // << 4 是将第一个字符的数值左移4位，相当于乘以16，然后加上下一个字符的数值
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        // 返回生成的字节数组
        return data;
    }

    /**
     * 根据id删除shp文件信息
     * @param id
     * @return
     * @author 窦凯欣
     */
    @Transactional
    @Override
    public Boolean deleteByid(Long[] id)

    {
        // 将数组转换为集合并批量删除
        List<Long> list = Arrays.asList(id);
        return this.removeBatchByIds(list);
    }
}
